package com.googlecode.jyoutubeuploader.parser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.log4j.Logger;

import com.google.gdata.util.common.SimpleCommandLineParser;

/**
 * @author tom
 *
 *	Parses and validates key/value pairs.
 *
 *	Design: it is stateless and it capable of working with any key/value pair.
 *	Parsers are registered with this class using a key that it is capable of parsing/validating
 *	and this class will delegate to these parser to do the work. If no parser is mapped for the
 *	supplied key, an exception will be thrown.
 *
 *	Functions this class should provide:
 *	-pretty print all arguments for debugging
 *	-validate all (known) arguments are valid
 *	-see if any unknown arguments are supplied (and say which ones)
 */
public class ModifiedCommandLineParser extends SimpleCommandLineParser implements CommandLineParser {

	private static final Logger logger = Logger.getLogger(ModifiedCommandLineParser.class);
	
	protected static final String USERNAME_ARG_SHORT = "u";
	protected static final String USERNAME_ARG_LONG = "username";
	protected static final String PASSWORD_ARG_SHORT = "p";
	protected static final String PASSWORD_ARG_LONG = "password";
	protected static final String FILE_ARG_SHORT = "f";
	protected static final String FILE_ARG_LONG = "file";
	protected static final String CATEGORY_ARG_SHORT = "c";
	protected static final String CATEGORY_ARG_LONG = "category";
	protected static final String TITLE_ARG_SHORT = "t";
	protected static final String TITLE_ARG_LONG = "title";
	protected static final String PRIVACY_ARG_SHORT = "v";
	protected static final String PRIVACY_ARG_LONG = "privacy";
	protected static final String DESCRIPTION_ARG_SHORT = "d";
	protected static final String DESCRIPTION_ARG_LONG = "description";
	protected static final String KEYWORDS_ARG_SHORT = "k";
	protected static final String KEYWORDS_ARG_LONG = "keywords";
	protected static final String THROTTLE_SPEED_ARG_SHORT = "t";
	protected static final String THROTTLE_SPEED_ARG_LONG = "throttle-speed";
	protected static final String REPORT_INTERVAL_ARG_SHORT = "r";
	protected static final String REPORT_INTERVAL_ARG_LONG = "report-interval";
	
	private static final List<String> knownArgs = Arrays.asList(new String[] {USERNAME_ARG_SHORT, USERNAME_ARG_LONG
			, PASSWORD_ARG_SHORT, PASSWORD_ARG_LONG, FILE_ARG_SHORT, FILE_ARG_LONG, CATEGORY_ARG_SHORT, CATEGORY_ARG_LONG
			, TITLE_ARG_SHORT, TITLE_ARG_LONG, PRIVACY_ARG_SHORT, PRIVACY_ARG_LONG, DESCRIPTION_ARG_SHORT
			, DESCRIPTION_ARG_LONG, KEYWORDS_ARG_SHORT, KEYWORDS_ARG_LONG, THROTTLE_SPEED_ARG_SHORT, THROTTLE_SPEED_ARG_LONG
			, REPORT_INTERVAL_ARG_SHORT, REPORT_INTERVAL_ARG_LONG});
	
	public ModifiedCommandLineParser(String[] arg) {
		super(arg);
	}

	public void printAllArguments() {
		List<String> unsuppliedArgs = new ArrayList<String>();
		for (int i = 0; i < knownArgs.size(); i++){
			categoriseCurrentArgument(unsuppliedArgs, i);
		}
		printFinalResults(unsuppliedArgs);
		
	}

	public void validateArguments() {
		//TODO revise this list, not everything is mandatory
		// Ensure there is a username
		Validate.isTrue(containsKey(USERNAME_ARG_SHORT) || containsKey(USERNAME_ARG_LONG)
				, getShortAndLongErrorMessage("Username", USERNAME_ARG_SHORT, USERNAME_ARG_LONG));
		
		// Ensure there is a password
		Validate.isTrue(containsKey(PASSWORD_ARG_SHORT) || containsKey(PASSWORD_ARG_LONG)
				, getShortAndLongErrorMessage("Password", PASSWORD_ARG_SHORT, PASSWORD_ARG_LONG));
		
		// Ensure there is a file
		Validate.isTrue(containsKey(FILE_ARG_SHORT) || containsKey(FILE_ARG_LONG)
				, getShortAndLongErrorMessage("The file to be uploaded", FILE_ARG_SHORT, FILE_ARG_LONG));
		
		// Ensure there is a category
		Validate.isTrue(containsKey(CATEGORY_ARG_SHORT) || containsKey(CATEGORY_ARG_LONG)
				, getShortAndLongErrorMessage("The video category", CATEGORY_ARG_SHORT, CATEGORY_ARG_LONG));
		
		// Ensure there is a title
		Validate.isTrue(containsKey(TITLE_ARG_SHORT) || containsKey(TITLE_ARG_LONG)
				, getShortAndLongErrorMessage("The video title", TITLE_ARG_SHORT, TITLE_ARG_LONG));
		
		// Ensure there is a privacy
		Validate.isTrue(containsKey(PRIVACY_ARG_SHORT) || containsKey(PRIVACY_ARG_LONG)
				, getShortAndLongErrorMessage("The video privacy", PRIVACY_ARG_SHORT, PRIVACY_ARG_LONG));
		
		// Ensure there is a description
		Validate.isTrue(containsKey(DESCRIPTION_ARG_SHORT) || containsKey(DESCRIPTION_ARG_LONG)
				, getShortAndLongErrorMessage("The video description", DESCRIPTION_ARG_SHORT, DESCRIPTION_ARG_LONG));
		
		// Ensure there are keywords
		Validate.isTrue(containsKey(KEYWORDS_ARG_SHORT) || containsKey(KEYWORDS_ARG_LONG)
				, getShortAndLongErrorMessage("The video keyword(s)", KEYWORDS_ARG_SHORT, KEYWORDS_ARG_LONG));
	}
	
	void printFinalResults(List<String> unsuppliedArgs) {
		if (unsuppliedArgs.size() > 0){
			logger.debug("Unsupplied arguments: " + StringUtils.join(unsuppliedArgs, ", "));
			return;
		}
		logger.debug("Unsupplied arguments: none");
	}

	void categoriseCurrentArgument(List<String> unsuppliedArgs, int i) {
		String currentArg = knownArgs.get(i);
		if (containsKey(currentArg)){
			logger.debug("Supplied argument: " + currentArg.trim() + " = " + getValue(currentArg));
			return;
		}
		unsuppliedArgs.add(currentArg);
	}

	String getShortAndLongErrorMessage(String prefix, String shortArg, String longArg){
		return prefix + " must be supplied, please use either the short (" + shortArg + ") or long (" 
			+ longArg + ") argument to supply it.";
	}
}
